Вот уже несколько раз я ругался странным словом ШИМ. Пора бы внести ясность и разьяснить что же это такое. Вообще, я уже расписывал этот режим работы, но все же повторюсь в рамках своего курса.
Вкратце, Широтно Импульсная Модуляция (в буржуйской нотации этот режим зовется PWM — Pulse Width Modulation) это способ задания аналогового сигнала цифровым методом, то есть из цифрового выхода, дающего только нули и единицы получить какие то плавно меняющиеся величины. Звучит как бред, но тем не менее работает. А суть в чем:
Представь себе тяжеленный маховик который ты можешь вращать двигателем. Причем двигатель ты можешь либо включить, либо выключить. Если включить его постоянно, то маховик раскрутится до максимального значения и так и будет крутиться. Если выключить, то остановится за счет сил трения.
А вот если двигатель включать на десять секунд каждую минуту, то маховик раскрутится, но далеко не на полную скорость — большая инерция сгладит рывки от включающегося двигателя, а сопротивление от трения не даст ему крутится бесконечно долго.
Чем больше продолжительность включения двигателя в минуту, тем быстрей будет крутится маховик.
При ШИМ мы гоним на выход сигнал состоящий из высоких и низких уровней (применимо к нашей аналогии — включаем и выключаем двигатель), то есть нулей и единицы. А затем это все пропускается через интегрирующую цепочку (в аналогии — маховик). В результате интегрирования на выходе будет величина напряжения, равная площади под импульсами.
Меня скважность (отношение длительности периода к длительности импульса) можно плавно менять эту площадь, а значит и напряжение на выходе. Таким образом если на выходе сплошные 1, то на выходе будет напряжение высокого уровня, в случае моего робота, на выходе из моста L293 это 12 вольт, если нули, то ноль. А если 50% времени будет высокий уровень, а 50% низкий то 6 вольт. Интегрирующей цепочкой тут будет служить масса якоря двигателя, обладающего довольно большой инерцией.
А что будет если взять и гнать ШИМ сигнал не от нуля до максимума, а от минуса до плюса. Скажем от +12 до -12. А можно задавать переменный сигнал! Когда на входе ноль, то на выходе -12В, когда один, то +12В. Если скважность 50% то на выходе 0В. Если скважность менять по синусоидальному закону от максимума к минимуму, то получим… правильно! Переменное напряжение. А если взять три таких ШИМ генератора и гнать через них синусоиды сдвинутые на 120 градусов между собой, то получим самое обычное трехфазное напряжение, а значит привет бесколлекторные асинхронные и синхронные двигатели — фетиш всех авиамоделистов. На этом принципе построены все современные промышленные привода переменного тока. Всякие Unidrive и Omron Jxx
В качестве сглаживающей интегрирующей цепи в ШИМ может быть применена обычная RC цепочка:
Так, принцип понятен, приступаем к реализации.
ШИМ сигнал можно сварганить и на операционных усилителях и на микроконтроллере. Причем последние умеют это делать просто мастерски, благо все у них для этого уже есть.
Аппаратный ШИМ
В случае ATMega16 проще всего сделать на его ШИМ генераторе, который встроен в таймеры. Причем в первом таймере у нас целых два канала. Так что без особого напряга ATmega16 может реализовать одновременно четыре канала ШИМ.
Как это реализовано
У таймера есть особый регистр сравнения OCR**. Когда значение в счётном регистре таймера достигнает значения находящегося в регистре сравнения, то могут возникнуть следующие аппаратные события:
- Прерывание по совпадению
- Изменение состояния внешнего выхода сравнения OC**.
Выходы сравнения выведены наружу, на выводы микроконтроллера
![]() |
На демоплате Pinboard к этим выводам как раз подключены светодиоды. А если поставить джамперы вдоль, в сторону надписи RC то к выводу ШИМ будет подключена интегрирующая цепочка.
Для Pinboard II разница в подключении невелика. Джамперы тут сгруппированы в один блок. А светодиоды и RC цепочки сгруппированы в левом верхнем углу платы.
Предположим, что мы настроили наш ШИМ генератор так, чтобы когда значение в счетном регистре больше чем в регистре сравнения, то на выходе у нас 1, а когда меньше, то 0.
Что при этом произойдет? Таймер будет считать как ему и положено, от нуля до 256, с частотой которую мы настроим битами предделителя таймера. После переполнения сбрасывается в 0 и продолжает заново.
Как видишь, на выходе появляются импульсы. А если мы попробуем увеличить значение в регистре сравнения, то ширина импульсов станет уже.
Так что меняя значение в регистре сравнения можно менять скважность ШИМ сигнала. А если пропустить этот ШИМ сигнал через сглаживающую RC цепочку (интегратор) то получим аналоговый сигнал.
У таймера может быть сколько угодно регистров сравнения. Зависит от модели МК и типа таймера. Например, у Атмега16
- Timer0 — один регистр сравнения
- Timer1 — два регистра сравнения (16ти разрядных!)
- Timer2 — один регистр сравнения
Итого — четыре канала. В новых AVR бывает и по три регистра сравнения на таймер, что позволяет одним МК организовать просто прорву независимых ШИМ каналов.
Самих режимов ШИМ существует несколько:
Fast PWM
В этом режиме счетчик считает от нуля до 255, после достижения переполнения сбрасывается в нуль и счет начинается снова. Когда значение в счетчике достигает значения регистра сравнения, то соответствующий ему вывод ОСхх сбрасыватся в ноль. При обнулении счетчика этот вывод устанавливается в 1. И все!
Частота получившегося ШИМ сигнала определяется просто: Частота процесора 8Мгц, таймер тикает до 256 с тактовой частотой. Значит один период ШИМ будет равен 8000 000/256 = 31250Гц. Вполне недурно. Быстрей не получится — это максимальная скорость на внутреннем 8Мгц тактовом генераторе. Но если переключить FUSE биты на внешний кварц то можно раскачать МК на 16Мгц.
Еще есть возможность повысить разрешение, сделав счет 8, 9, 10 разрядным (если разрядность таймера позволяет), но надо учитывать, что повышение разрядности, вместе с повышением дискретности выходного аналогового сигнала, резко снижает частоту ШИМ.
Phase Correct PWM
ШИМ с точной фазой. Работает похоже, но тут счетчик считает несколько по другому. Сначала от 0 до 255, потом от 255 до 0. Вывод OCxx при первом совпадении сбрасывается, при втором устанавливается.
Но частота ШИМ при этом падает вдвое, изза большего периода. Основное его предназначение, делать многофазные ШИМ сигналы, например, трехфазную синусоиду. Чтобы при изменении скважности не сбивался угол фазового сдвига между двумя ШИМ сигналами. Т.е. центры импульсов в разных каналах и на разной скважности будут совпадать.
Еще одна тонкость:
Чтобы не было кривых импульсов, то в регистр сравнения любое значение попадает через буфферный регистр и заносится только тогда, когда значение в счетчике достигнет максимума. Т.е. к началу нового периода ШИМ импульса.
Clear Timer On Compare
Сброс при сравнении. Это уже скорей ЧИМ — частотно-импульсно моделированный сигнал. Тут работает несколько иначе, чем при других режимах. Тут счетный таймер тикает не от 0 до предела, а от 0 до регистра сравнения! А после чего сбрасывается.
![]() |
В результате, на выходе получаются импульсы всегда одинаковой скважности, но разной частоты. А чаще всего этот режим применяется когда надо таймером отсчитывать периоды (и генерить прерывание) с заданной точностью.
Например, надо нам прерывание каждую миллисекунду. И чтобы вот точно. Как это реализовать проще? Через Режим СТС! Пусть у нас частота 8Мгц.
Прескалер будет равен 64, таким образом, частота тиков таймера составит 125000 Гц. А нам надо прерывание с частотой 1000Гц. Поэтому настраиваем прерывание по совпадению с числом 125.
Дотикал до 125 — дал прерывание, обнулился. Дотикал до 125 — дал прерывание, обнулился. И так бесконечно, пока не выключим.
Вот вам и точная тикалка.
Нет, конечно, можно и вручную. Через переполнение, т.е. дотикал до переполнения, загрузил в обработчике прерывания заново нужные значение TCNTх=255-125, сделал нужные полезные дела и снова тикать до переполнения. Но ведь через СТС красивей! :)
Аппаратура
А теперь контрольные регистры, которыми все это безобразие задается и программируется. Опишу на примере Двухканального FastPWM на таймере 1. В других все похоже. Даташит в зубы и вперед.
Итак, тут правят бал регистры TCCR1A и TCCR1B. Гы, кто бы сомневался %)
Распишу их по битам.
Регистр TCCR1A, биты COM1A1:COM1A0 и COM1B1:COM1B0. Эта братия определяет поведение вывода сравнения OC1A и OC1B соответственно.
COMxx1 | COMxx0 | Режим работы выхода |
0 | 0 | вывод отцеплен от регистра сравнения и не меняется никак. |
0 | 1 | Поведение вывода зависит от режима заданного в WGM, различается для разных режимов (FastPWM, FC PWM, Compar out) и разных МК, надо сверяться с даташитом. |
1 | 0 | прямой ШИМ (сброс при совпадении и установка при обнулении счета) |
1 | 1 | обратный ШИМ (сброс при обнулении и установка при совпадении) |
Регистр TCCR1A, биты WGM11 и WGM10 вместе с битами WGM12 и WGM13, находящимися в регистре TCCR1B задают режим работы генератора.
WGM13 | WGM12 | WGM11 | WGM10 | Режим работы |
0 | 1 | 0 | 1 | Fast PWM 8 бит |
0 | 1 | 1 | 0 | Fast PWM 9 бит |
0 | 1 | 1 | 1 | Fast PWM 10 бит |
Другие комбинации битов WGM задают режимы Phase Correct PWM и CTC (сброс OCxx при совпадении). Если интересно, то читай даташит, я для себя много интересного там не нашел, кроме Phase Correct PWM. И то мне сейчас важней скорость, а не точность фазы :)
После остается только запустить таймер, установив бит CS10 (подсчет тактовых импульсов с делителем 1:1)
Пример кода:
Попробуем поиграться яркостью светодиодов с помощью ШИМ сигналов. Подключи джамперы, чтобы запитать светодиоды LED1 и LED2

Для версии Pinboard II все аналогично, с поправкой на другое расположение джамперов:

Теперь все готово, можно писать код. Вначале в раздел инициализации устройств добавляю настройку таймера на запуск ШИМ и подготовку выводов.
1 2 3 4 5 6 7 8 9 10 11 12 | ;FastPWM Init SETB DDRD,4,R16 ; DDRD.4 = 1 Порты на выход SETB DDRD,5,R16 ; DDRD.5 = 1 ; Выставляем для обоих каналов ШИМ режим вывода ОС** сброс при совпадении. ; COM1A = 10 и COM1B = 10 ; Также ставим режим FAST PWM 8bit (таймер 16ти разрядный и допускает ; большую разрядность ШИМ сигнала. Вплоть до 10 бит. WGM = 0101 ; Осталось только запустить таймер на частоте МК CS = 001 OUTI TCCR1A,2<<COM1A0|2<<COM1B0|0<<WGM11|1<<WGM10 OUTI TCCR1B,0<<WGM13|1<<WGM12|1<<CS10 |
Готово! Теперь ШИМ таймера1 генерит сигнал на выходаx OC1А и OC1B
Закинем в регистры сравнения первого и второго канала число 255/3=85 и 255/2 = 128
Так как ШИМ у нас 8ми разрядный, то заброс идет только в младший разряд. Старший же остается нулем. Но регистры сравнения тут у нас 16ти разрядные поэтому грузить надо оба байта сразу. Не забыв запретить прерывания (это важно!!! ибо атомарный доступ)
1 2 3 4 5 6 7 | CLI OUTI OCR1AH,0 OUTI OCR1AL,85 OUTI OCR1BH,0 OUTI OCR1BL,128 SEI |
Поехали! :)
Прошиваем, тыкаемся в ноги микроконтроллера осциллографом — видим следующую картину по каналам:
![]() |
Как мы и запланировали. С первого канала длительность импульса в 1/3 периода, а со второго в 1/2
Ну и светодиоды горят с разной яркостью. Один ярче, другой тусклей. Меняя значение в регистрах OCR*** мы можем менять скважность.
Давай сделаем так, чтобы светодиод плавно менял свою яркость от нуля до максимума. Как помнишь, у нас там была программа, с мигающем по таймеру0 светодиодом. Немного ее подправим, сделаем так, чтобы по таймеру не светодиод мигал, а менялось значение в регистрах сравнения OCR1A и OCR1B. Причем меняться оно будет в разные стороны :)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | ; Main ========================================================= Main: LDS R16,TCNT ; Грузим числа в регистры LDS R17,TCNT+1 CPI R16,0x10 ; Сравниванем побайтно выдержку BRCS NoMatch CPI R17,0x01 ; Выдержку сделали поменьше = 0x0110 BRCS NoMatch ; Если совпало то делаем экшн Match: CLI ; Запрет прерываний, т.к. атомарный доступ ; Меняем первый канал ; Особенность 16ти разрядных регистров в том, что их надо правильно читать и записывать. ; Читают вначале младший, потом старший байты. Так надо, чтобы младший не успел измениться ; (он ведь может тикать по таймеру) пока читают первым старший. Укладывают их в обратном ; порядке. Сначала старший, потом младший. Правда для регистров OCR это не имеет большой ; разницы -- они статичные, а вот для TCNT очень даже! IN R16,OCR1AL ; Достали первый байт сравнения IN R17,OCR1AH ; он 16ти разрядный, но старший байт будет 0 INC R16 ; Увеличили OUT OCR1AH,R17 ; И сунули их обратно OUT OCR1AL,R16 ; Меняем второй канал IN R16,OCR1BL ; Достали второй байт сравнения IN R17,OCR1BH ; он 16ти разрядный, но старший байт будет 0 DEC R16 ; Уменьшили OUT OCR1BH,R17 ; И сунули их обратно OUT OCR1BL,R16 SEI ; Конец атомарного доступа ; Теперь надо обнулить счетчик, иначе за эту же итерацию главного цикла ; Мы сюда попадем еще не один раз -- таймер то не успеет натикать 255 значений ; чтобы число в первых двух байтах счетчика изменилось. CLR R16 ; Нам нужен ноль CLI ; Таймер меняется и в прерывании. Нужен ; атомарный доступ. Запрещаем прерывания OUT TCNT0,R16 ; Ноль в счетный регистр таймера STS TCNT,R16 ; Ноль в первый байт счетчика в RAM STS TCNT+1,R16 ; Ноль в второй байт счетчика в RAM STS TCNT+2,R16 ; Ноль в третий байт счетчика в RAM STS TCNT+3,R16 ; Ноль в первый байт счетчика в RAM SEI ; Разрешаем прерывания. ; Не совпало - не делаем :) NoMatch: NOP INCM CCNT ; Шарманка вращается дальше, вхолостую JMP Main |
А теперь давайте включим режим с точной фазой (WGM = 0001) и посмотрим на то как будет меняться скважность.
1 2 | OUTI TCCR1A,2<<COM1A0|2<<COM1B0|0<<WGM11|1<<WGM10 OUTI TCCR1B,0<<WGM13|0<<WGM12|1<<CS10 |
ШИМ на прерываниях.
Но вот засада — плата уже разведена, захотелось ШИМ, а выводы OCxx уже задействованы под другие цели.
Ничего страшного, малой кровью можно это исправить. Также запускаем ШИМ, только:
- Отключаем выводы OCxx от регистра сравнения.
- Добавляем два обработчика прерывания на сравнение и на переполнение. В прерывании по сравнению сбрасываем нужный бит, в прерывании по переполнению счетчика устанавливаем.
Все просто :)
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;FastPWM Init на прерываниях ; ШИМ будет на выводах 3 и 6 порта D SETB DDRD,3,R16 ; DDRD.3 = 1 Порты на выход SETB DDRD,6,R16 ; DDRD.6 = 1 ; Выставляем для обоих каналов ШИМ режим вывода ОС** выключеным. ; COM1A = 00 и COM1B = 00 ; Также ставим режим FAST PWM 8bit (таймер 16ти разрядный и допускает ; большую разрядность ШИМ сигнала. Вплоть до 10 бит. WGM = 0101 ; Осталось только запустить таймер на частоте МК CS = 001 OUTI TCCR1A,0<<COM1A0|0<<COM1B0|0<<WGM11|1<<WGM10 OUTI TCCR1B,0<<WGM13|1<<WGM12|1<<CS10 SETB TIMSK,OCIE1A,R16 ; Включаем прерывание по сравнению А SETB TIMSK,OCIE1B,R16 ; Включаем прерывание по сравнению Б SETB TIMSK,TOIE1,R16 ; Включаем прерывание по переполнению Т1 ; Причем в режиме WGM=1010 переполнение ; будет на FF т.е. таймер работает как ; 8ми разрядный. |
Осталось только прописать обработчики и вектора:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | .CSEG .ORG $000 ; (RESET) RJMP Reset .ORG $002 RETI ; (INT0) External Interrupt Request 0 .ORG $004 RETI ; (INT1) External Interrupt Request 1 .ORG $006 RETI ; (TIMER2 COMP) Timer/Counter2 Compare Match .ORG $008 RETI ; (TIMER2 OVF) Timer/Counter2 Overflow .ORG $00A RETI ; (TIMER1 CAPT) Timer/Counter1 Capture Event .ORG $00C RJMP Timer1_OCA ; (TIMER1 COMPA) Timer/Counter1 Compare Match A .ORG $00E RJMP Timer1_OCB ; (TIMER1 COMPB) Timer/Counter1 Compare Match B .ORG $010 RJMP Timer1_OVF ; (TIMER1 OVF) Timer/Counter1 Overflow .ORG $012 RJMP Timer0_OV ; (TIMER0 OVF) Timer/Counter0 Overflow .ORG $014 RETI ; (SPI,STC) Serial Transfer Complete .ORG $016 RETI ; (USART,RXC) USART, Rx Complete .ORG $018 RETI ; (USART,UDRE) USART Data Register Empty .ORG $01A RETI ; (USART,TXC) USART, Tx Complete .ORG $01C RETI ; (ADC) ADC Conversion Complete .ORG $01E RETI ; (EE_RDY) EEPROM Ready .ORG $020 RETI ; (ANA_COMP) Analog Comparator .ORG $022 RETI ; (TWI) 2-wire Serial Interface .ORG $024 RETI ; (INT2) External Interrupt Request 2 .ORG $026 RETI ; (TIMER0 COMP) Timer/Counter0 Compare Match .ORG $028 RETI ; (SPM_RDY) Store Program Memory Ready .ORG INT_VECTORS_SIZE ; Конец таблицы прерываний ; Interrupts ============================================== Timer0_OV: PUSHF PUSH R17 PUSH R18 PUSH R19 INCM TCNT POP R19 POP R18 POP R17 POPF RETI ; Вот наши обработчики на ШИМ Timer1_OCA: SBI PORTD,3 RETI Timer1_OCB: SBI PORTD,6 RETI Timer1_OVF: CBI PORTD,3 CBI PORTD,6 RETI ; End Interrupts ========================================== |
Почему я в этих обработчиках не сохраняю регистры и SREG? А незачем! Команды SBI меняют только конкретные биты (а больше нам и не надо), не влияя на флаги и другие регистры.
Запустили…
И получили полную херню. Т.е. ШИМ как бы есть, но почему то адово мерцает. А на осциллографе в этот момент полный треш. Кто виноват? Видимо конфликт прерываний. Осталось только выяснить где именно. Сейчас я вам дам практический пример реалтаймовой отладки :)
Итак, что мы имеем:
ШИМ, как таковой, работает. Скважность меняется. Значит наш алгоритм верен.
Но длительности скачут. Почему? Видимо потому, что что-то мешает им встать вовремя. Когда у нас возникают фронты? Правильно — по прерываниям. А прерывания по таймерам. Т.е. врать не должны. Однако так получается. Давайте узнаем каком месте у нас конфликт.
Первым делом надо добавить в код обработчика отладочную инфу. Будем в обработчике прерываний инвертировать бит. Пусть это будет PD7 — зашли в обработчик, инверснули. Зашли — инверснули. В результате, у нас на выходе этого бита будет прямоугольный сигнал, где каждый фронт — сработка прерываний. Послужит нам как линейка, отмеряющая время.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ; Interrupts ============================================== Timer0_OV: PUSHF PUSH R17 PUSH R18 PUSH R19 INCM TCNT POP R19 POP R18 POP R17 POPF RETI ; Установка бита ШИМ канала А Timer1_OCA: SBI PORTD,3 RETI ; Установка бита ШИМ канала Б Timer1_OCB: SBI PORTD,6 RETI ;Сброс бита ШИМ канала А и Б Timer1_OVF: CBI PORTD,3 CBI PORTD,6 ;DEBUG PIN BEGIN --------------- PUSHF INVBM PORTD,7 POPF ;DEBUG PIN END ----------------- RETI |
Инверсия бита невозможна без логических операций, поэтому надо сохранять флаги.
Из картинки стало понятно, что у нас накрывается прерывание по сравнению. Давайте попробуем посмотреть с какими прерыванием происходит конфликт. Особых вариантов у нас нет — прерываний у нас тут четрые. А наиболее очевиден конфликт Timer0_OV vs Timer1_OCA vs Timer1_OCB.
OCA и OCB конфликтуют только тогда, когда счетные регистры у них сравниваются — вызов происходит почти одновременно, но сами обработчики короткие — всего несколько тактов, поэтому дребезг не столь сильный.
А вот Timer0_OV делает довольно мощный прогруз стека и еще вычитает четырехбайтную переменную. Т.е. тактов на 20 может задержать обработчик установки бита Timer1_OC* от того и вылазят такие зверские дребезги.
Давайте проверим эту идею. Разрешим прерывания в обработчике Timer0_0V
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ; Interrupts ============================================== Timer0_OV: SEI PUSHF PUSH R17 PUSH R18 PUSH R19 INCM TCNT POP R19 POP R18 POP R17 POPF RETI ; Установка бита ШИМ канала А Timer1_OCA: SBI PORTD,3 RETI ; Установка бита ШИМ канала Б Timer1_OCB: SBI PORTD,6 RETI ;Сброс бита ШИМ канала А и Б Timer1_OVF: CBI PORTD,3 CBI PORTD,6 RETI |
Картина сразу исправилась. Теперь более важное (для нас важное) прерывание задвигает обработчик от Таймера 0. Но тут надо просекать возможные риски:
- Более глубокий прогруз стека
- Нарушается атомарный доступ к четырехбайтной переменной TCNT, поэтому если бы у нас было еще какое-то прерывание, меняющее TCNT то его надо было бы запрещать локально. Иначе бы мы получили такой трешняк, что проще заново прогу переписать, чем это отладить
.
ШИМ на таймерах
Когда совсем все плохо, то можно сделать на любом таймере. В обработчик прерывания по переполнению таймера заносим конечный автомат, который сначала загрузит в таймер длительность низкого уровня, а при следующем заходе — длительность высокого. Ну и, само собой, ноги процессора подергает как надо. Таким образом, на один таймер можно повесить дофига ШИМ каналов, но задолбаешься все с кодовой реализацией всего этого. И процессорное время жрать будет некисло. Не говоря уже про дребезги, о которых только что было сказано. Это для эстетов извращенцев :)))))
Исходник к статье
А где у тебя резистор в RС фильтре который ШИМ в аналог превращает? =)
А Shit! Я про него вечно забываю :)))))) Вообще по хорошему туда бы еще и дроссель воткнуть :))))
Только хотел сказать про резюк, а забывать нельзя.
Ну на счёт дросселя не скажу =) У меня с индуктивностями отношения тяжелые =)
А без резюка можно и вывод у ШИМ-генератора спалить. На выходе получается перманентная «КоЗа» =)
Ага, кондер же подсаживает когда неразряжен.
Диод затем LC
или какая коза имеется ввиду
Имеется в виду коза при первоначально разряженном конденсаторе.Разряженный конденсатор в самый первый момент времени подобен перемычке.
У меня есть на tiny13 управление трёхцветным диодом. Так там 3 канала ШИМ реализованы совершенно тупо — в главном цикле программы. А вот уже управление. когда какую мощность на какой канал выдать, живёт по прерываниям от таймера.
Наизнанку чтоль? Писец.
Замечательно пишешь, читается очень легко!
Добавлю от себя: современные промышленные бесколлекторные асинхронные двигатели управляются обычно по принципу «двухполярной ШИМ», где каждый её полюс «склеивают» из пары Phase Correct PWM и соответственно пары ключей.
«Phase Correct PWM» по-русски иногда называют «симметричной ШИМ»
а в каких пределах будет выход с контроллера? От плюс питающего до нуля?
Да
Здравствуйте, инициализовал вот таким образм, как написано у вас в статье:
LDI R16,(1<<COM1A1)|(1<<COM1B1)|(1<<WGM10) ; Инициализация PWM
OUT TCCR1A, R16
LDI R16,(1<<WGM12)|(1<255,0->255
В счётном регистре должно считаться от 0 до 255, потом сразу 0. А у меня считает от 0 до 255, потом до 0 в обратную сторону.
Вообщем должен считать: 0->255,0->255
А он считает : 0->255->0,0->255->0.
Моделирую в AVR Studio.
В чём может быть проблема? В неправильной инициализации или это AVR Studio не прпвильно работает?
У тебя получился режим точной фазы. В нем считает так. Позырь в своем даташите по поводу режимов.
Режим точной фазы нужен для создания многофазной системы ШИМ, чтобы когда меняешь скважность на разных каналах не происходил фазовый сдвиг (начала периодов) разных каналов между собой.
В общем, разберись с битами WGM и выстави режим Fast PWM
Я использую ATmega8
Сверился с документацией,биты PWM13,PWM12,PWM11,PWM10
0 1 0 1
означают режим FAST PWM,8-bit
Счётный регистр же не смотря на все эти доводы продолжает счиать от 0 до 255 и в обратном направлении… уже не знаю как убедить его рабоать как надо… проверял осциллографом на OC1A и OC1B никаких импульсов нету(
скинь мне проект, погляжу. А то код инициализации что ты мне запостил какой то побитый получился. Сам погляди.или запости сюда код инициализации его как есть, копипастом, окружив в теги:<pre lang=»AVR» line=»1″></pre>
ХА! Да, ты прав. АВР студия глючит нипадецки! Это уже второй ее глюк на Мега8 Гыгыгы. У меня тоже считает в режиме точной фаз, хотя на самом деле работает все ок.
Это два канала моих ОС1В и ОС1А на одном порог стоит в 10 на другом в 100. Режим Быстрый ШИМ. Будь он Точной фазой центры импульсов бы совпадали. Значит работает верно — в студии же глючит. Инициализация кода вот такая:
Ах это проклятая AVR Studio значит)
А вот про направление портов я и забыл!… вот причина моих бед.
Спасибо за оперативные ответы, на осциллографе всё полный порядок))
«Когда значение в счётном регистре таймера достигнет значения находящегося в счетном регистре, то могут возникнуть следующие аппаратные события.»
Масло маслянное — чета тут видимо очепятка. Наверно достигнет значения одного из регистров сравнения…
«Можно повысить разрешение, сделав счет 8, 9, 10 разрядным, но надо учитывать, что повышение разрядности, вместе с повышением дискретности выходного аналогового сигнала, резко снижает частоту ШИМ.»
Не всосал чет. Вроде счет и так 8-разрядный (делишь частоту на 256). И не понял почему резко снизится частота ШИМ при увеличении разрядности. Я так понял на каждый бит увеличения — частота снижается вдвое. да?
Еще в таблице COMxx1:COMxx0 вторая строка — там написано Иначе не отцеплен, тогда смысл непонятен. Может всетаки Иначе ОН отцеплен ?
А как вы на осциллографе смотрите в студии? чет не нашел я его.
Ну так на 8ми разрядном делишь частоту на 256, на 9ти разрядном на 512, а на 10 делить придется уже на 1024.
В студии нет осциллографа. А это просто скриншоты с моего осциллографа.
Доброго времени суток! Может вопрос не в тему, но задам таки. В проекте в PPOTEUS мне нужно использовать ATmega8 вместе с SG3525. Но, если ATmega8 есть в библиотеке PROTEUS, то SG3525 нет. Может кто подскажет где взять библиотечку с SG3525 для PROTEUS. А то вконец работа остановилась! SG3525 в проекте управляет полевиками, работающими на плечи первичной обмотки со средней точкой импульсного трансформатора. Буду очень благодарен. С наступающим праздником Днем защитника Отечества!
Частота получившегося ШИМ сигнала определяется просто: Частота процесора 8МГц, таймер Т/С1 тикает до 256 с тактовой частотой. Значит один период ШИМ будет равен 8000 000/256 = 31250Гц. Вполне недурно.
Быстрей не получится — это максимальная скорость на внутреннем 8МГц тактовом генераторе. Можно повысить разрешение, сделав счет 8, 9, 10 разрядным, но надо учитывать, что повышение разрядности, вместе с повышением дискретности выходного аналогового сигнала, резко снижает частоту ШИМ.
———
есть задача в противоположном.. как понизить разрядность? (7[127],6[64])
тем самым повысить частоту ШИМ в 2,4 раз соответственно..
есть ндобоство так сказать
Аппаратно никак. Только делать программно.
согласен сам думал что програмно.. но сказано что пробегает значения от 0(=1) до 255 .допустим у нас 127(=0).. и как тут програмно немогу понять, ведь 1 раз выставляется 0 и 1 за цикл от0до255
хотябы 7 разрядноять расмотрим
Считаешь от 0 до смены состояния, меняешь состояние, загружаешь новый счет, считаешь от текущего до следующего. Тут можно много напридумывать вариантов. Используя прерывания от таймера.
расмотрим 7 разрядность 0..127
тоесть задали мы число 55
1(начало)1111….1110(это наше число 55 — мы до него дошли)0000…….0000(стоп — мы дошли до 127) — получили инфу что счетчик дошел до 127 и прерыванием сбрасываем(загружаем новый счет). и т.д.
?
Нет, допустим граница у нас 64
А надо получить ШИМ 50%
Считаем до 64-50%=32 по прерыванию меняем сигнал на ноге, закладываем новый cчет равный 64-(64-50%)=32 и считаем опять до прерывания. ГДе все повторяется
Обьясни пожалуйста. Если режим ШИМ реализован на таймере, то как так может быть что таймера 2, а ШИМ канала 4? Как в ATtiny2313 например…
Легко. Если ты обратишь внимание, то в каждом таймере есть по два регистра сравнения. И каждый из них может быть задействован на перещёлкивание своего вывода: OC0A, OC0B, OC1A, OC1B
Тоесть, один таймер может обеспечивать 2 ШИМ канала с независимой скважностью?
Да, именно так. Но не всегда, зависит от того сколько регистров сравнения имеет таймер.
Подскажите как правильно рассчитать номиналы для интегрирующей цепочки на выходе?
например у меня ATTiny2313 кварц на 20 Mhz. Режим ШИМ — быстрый. Таймер 8 бит. Частота ШИМ получается 78125 hz. Интересует сам алгоритм чтобы я мог его применить и для других частот ШИМ.
У RC цепочки есть параметр — постоянная времени T. Это время за которое заряд изменится втрое. Соответственно Т должно быть таким, чтобы конденсатор не успевал перезаряжаться, то есть два три периода ШИМ сигнала.
Т=R*C
DI HALT, еще раз спасибо за хороший сайт!
Сегодня собрал макетку COM->МК->двигатель (MAX232->Mega8->L293D).
Воткнул одним концом в комп, другим — в отобранную у ребенка машинку.
Работает, однако! =)
Вопрос про ШИМ:
При моей схеме куда пихать RC цепочку (и нужна ли она здесь вообще)?
Тебе не особо там. Т.к. у тебя неслабым фильтром служит двигатель (индуктивность обмоток). Разве что между щетками движка поставить кондерчик на 100нанофарад.
Ага, спасибо.
Пожалуйста посмотри, правильно ли я понял:
RC-цепочка нужна, когда инерционности самой нагрузки не хватает? Например для лампы. И этом случае она втыкается между последним цифровым компонентом (с которого идет ШИМ) и аналоговой частью.
Например, в моем случае ШИМ-сигнал формируется контроллером, но ровно в такой же форме он проходит через L293D. Т.о. L293D — последний цифровой компонент. А вот дальше уже должен быть аналоговый сигнал, соответственно если и нужна RC-цепочка, то сразу после L293D.
Так?
Да понял правильно. RC образует фильтр который из пульсирующего вычленяет переменную составляющую. Остается только переменка.
При питании мощной нагрузки RC не ставят, во первых потому, что тогда будут дикие потери на R, во вторых нет особой нужды — индуктивности обмоток вполне хватит, чтобы сгладить напряжение до постоянки, кроме того, существует еще огромная (по сравнению с частотой) инерция ротора двигателя, так что импульсы там сгладятся в постоянку.
С лампой, кстати, RC тоже не нужна — нить накала обладает большой температурной инерцией.
А вот подавать на вход ОУ в качестве опорного сигнала напрямую с ШИМ нельзя — надо фильтровать.
Ок, понял. Спасибо.
ШИМ, как ни странно, тоже заработал почти сразу (забыл сначала инициализацию порта на выход вставить). Теперь руки чешутся плату развести, чтобы установить это все богатство на шасси.
В этой связи вопрос:
Какой-нибудь статьи про разводку плат не планируется? ;-)
Уже при трех микросхемах как-то все не просто получается, а ведь туда еще питание с землей надо, и подключения наружу должны торчать. Макетка напоминает то ли блюдо со спагетти то ли прическу жены утром =)
Второй день перечитываю эту_статью-статью_с_gaw.ru-даташит. Никак не могу достьчь просветления =) Голова не соображает что-то..
Работаю в CodeVision.
// Выставляем порты
PORTB=0xFF; // порт
DDRB=0xFF; // на выход
PORTD=0xFF; // порт
DDRD=0×00; // на вход
Далее нужно сконфигурировать таймер.
TCCR1A=??; //
TCCR1B=??; //
И в нужный нам момент кинуть в регистр сравнения число.
Есть несколько вопросов:
1.) Распишите побитово TCCR1A, TCCR1B, пожалуйста
2.) Число можно кидать в любое время в любом месте? Или нет? Можно например в главном цикле написать OCR1A=PORTD? Изменяя переключателями значение PORTD изменяем скважность.
3.) После инициализации и заброса значений ШИМ работает автоматом? Т.е. надо ли что-нибудь подправлять, закидывать снова?
PS: не думал, что так запутанно будет.. Привык на VB писать, развратил он меня в край =)
Там же есть пример кода и в нем написано в какой регистр что записывается для запуска FastPWM. После инициализации заработает автоматом, ага.
Число можно закидывать в регистр сравнения когда угодно.
с TCCR1A я примерно разобрался. На Гав.ру http://www.gaw.ru/html.cgi/txt/doc/micros/avr/arh/mega103_39.htm. TCCR1B выглядит не так. Там нет бит WGM13 WGM12, да и, кстати в TCCR1A нет WGM11 WGM10. А в той доке на Гав вообще как-то запутанно: есть ШИМ режим, и не ШИМ режим. И как переходить на ШИМ режим не написано. В принципе я твой код понял, но у меня нет значений констант COM1A1, COM1B1, WGM10, WGM12, CS10.
биты WGM это биты PWM и так далее, их почему то переименовали в некоторых МК, тут только читать даташит.
Вроде осилил, поздравьте меня =) К тому же оказалось, что я писал OCR1A=PORTD, а надо было OCR1AL=PIND. Мало того, что OCR1A 16ти-битный, ещё и когда читаем значение, то писать надо PIN, а не PORT.
Ну так само собой. Читать порт надо из пина, порт это регистр вывода/конфигурации.
..шим очишуенная штуковина.. но косячек один есть который заключается в том что в тот самый счетчик на котором все работает нельзя вносить коррекцию в процессе работы этого самого шим, сравнения и прочего, так как момент непосредственного присвоения счетчику нужного значения — сравнения прерываются и этот момент выпадает, и прерывания по совпадению значений счетчика и содержимого регистра сравнения не происходит т.к. в этот момент регистр счетчика занят.. ..отстой.. :(
Подскажите, а как программно реализовать мертвое время, если это возможно?
Эмм а в чем проблема? Подаешь управляющие импульсы на ключи со смещением и все. Или ты что имеешь ввиду?
Можно сделать на двух таймерах. Т.е. первый работает в ШИМ режиме, но ОС отключен от ноги МК — нам нужны только два его прерывания OCF и OVF по этим прерываниям мы запускаем второй таймер который и отсчитает нам дедтайм, а потом переключит ногу в своем прерывании.
Либо конечный автомат на одном таймере. С четырьмя состояниями. Вверх, дедтайм, вниз, дедтайм.
Вроде сообразил. Мне нужно было на одном таймере, сделать два шима, скважность регулируется с помощью ацп. Сделал так: в прерывании от ацп к регистру OCR1A прибавил константу (половина dead time), а от OCR1B отнял ту же константу, вроде работает.
А что если поставить конденсатор большой емкости на ШИМ выход? По идее получим же более сглаженный сигнал же, устраним микрорывки.
Поможет, но ты потеряешь в динамичности. Т.е. при быстром изменении скважности ШИМ твой кондер может не успеть перезарядиться. Тут надо думать :)
Сделал шим на 3 светодиода на таймере 1 и таймере 2. Когда ставлю в OCRxx 0, светодиоды притухают, но не гаснут полностью.
Попробовал менять значения от 0 до 255, яркость плавно нарастает, потом светодиоды притухают, но опять же не гаснут полностью.
В чём может быть косяк?
Хм. Покажи код инициализации. Должны на нуле гаснуть.
Вот код. Осцилографа пока нет, чтобы проверить.
;Init PWM timers
;Timer 1
ldi OTEMP,$A1
out TCCR1A,OTEMP ;8-bit Fast PWM C(t)=CLK/1
ldi OTEMP,$09
out TCCR1B,OTEMP
ldi OTEMP,65
out OCR1AL,OTEMP ;
ldi OTEMP,140
out OCR1BL,OTEMP ;
;Timer 2
ldi OTEMP,$69 ;8-bit Fast PWM C(t)=CLK/1
out TCCR2,OTEMP
ldi OTEMP,200
out OCR2,OTEMP ;Duty Cycle = 0%
Вот код. Осцилографа пока нет, чтобы проверить.
;Init PWM timers
;Timer 1
ldi OTEMP,$A1
out TCCR1A,OTEMP ;8-bit Fast PWM C(t)=CLK/1
ldi OTEMP,$09
out TCCR1B,OTEMP
ldi OTEMP,65
out OCR1AL,OTEMP ;
ldi OTEMP,140
out OCR1BL,OTEMP ;
;Timer 2
ldi OTEMP,$69 ;8-bit Fast PWM C(t)=CLK/1
out TCCR2,OTEMP
ldi OTEMP,200
out OCR2,OTEMP ;
Да вроде бы все верно. Должна скважность меняться от 0 до 100%
DI HALT, спасибо… действительно всё верно. Светодиоды такие чувствительные попались, заразы. Если двумя руками взяться за выводы, они даже так начинают слабенько светить. Другие светодиоды гаснут нормально :)
Обана. Что это за светики такие? модель назвать можешь?
модель не назову. умыкнул с одного электронного завода пакетик. обычные 5мм в прозрачных корпусах.
могу ли я сделать цифровой процессор (преобразователь «аналог-ШИМ») на AtMega8 или на ATtiny85 с целью подать потом полученный сигнал на усилитель D-класса работающий в ключевом режиме?. если да то какой из них наиболее лучше подойдет? и еще, можно ли получить несущую частоту (шим)150-400 кГц аппаратно или программно?
Ммм… частоты не шуточные. АВРКА может и не успеть. Считай максимальная частота шим с 8ми разрядным ШИМ у ней будет как тактовая /8 тактовая предельная (для некоторых АВР) 20мгц так что максимум ты из нее выжмешь 250кГц. попробовать можно.
ой 2.5МГЦ !!! Ващет успеть можно :))))
в принципе 250 кгц вполне хватит, мне качество звука маловажен, главное чтоб работало!
Подскажите как расчитывать резистор RC фильтра на выходе ШИМ после силовых мосфетов. Конденсатор я расчитал по формуле емкостного сопротивления. Резистор должен быть расчитан относительно максимально допустимого тока силовых мосфетов?
А зачем после силовых мосфетов ставить RC? Так обычно не делают (будут дикие потери на резисторах) Тут делают LC фильтр с обратным диодом.
В общем я так и сам думал что он не нужен, есть реально работающая схема без резистора, ток нагрузки 8А транзисторы на 50А пиковой. Очень интересует необходимость ставить кондер параллельно индуктивной нагрузке(двигатель постоянного тока) Вот приблизительная схема того что у нас будет: http://infarct.nm.ru/Files/U102Hbridge.pdf Мне просто кажется что в движке будут жуткие индуктивные потери, кондер собираюсь ставить на 20 микрофарад пленочный или бумажный. Мост будет использоваться на симуляторе автомобиля, собранного на разогнанном микроконтроллере и дополнительном PC с управлением через COM порт. Вот ссылка http://mal4x.org.ru/forum/topic.php?forum=2&topic=51&v=|#1270560902
В дальнейшем планируем разработать свою прошивку, так как оригинальная нас многим не устраивает, в частности своей глючностью. Исходники автор не выкладывает, но как мне кажется вполне реально самому разобраться и сделать ШИМ контроллер с обратной связью через датчик Холла или потенциометр.
Для движка нафига там вообще какие то индуктивности и фильтры? Там сам по себе якор индуктивность та еще.
Индуктивность у движка присутствует, я в курсе, не про то спрашивал, нужен ли кондер параллельно ему?
Нет. Он даст ненужный бросок тока.
А как же быть с индуктивными потерями на движке? У нас частота шим модуляции 24 КГц, он хоть и крутится, но ощутимо греется, хотелось бы чтобы места тепла было побольше КПД выраженного в механической энергии. Может там все таки поставить кондер, но небольшой емкости?
Получишь бросок тока на ключ и емкостные потери. Если ставить, то LC фильтр, чтобы L сгладила бросок тока через кондер. Но потеряешь в динамичности привода. Он станет более ленивым чтоль. А греться он будет и так и так.
Здравствуйте! Пытаюсь сгенерировать синусоиду ШИМом на ATmega16u4. Кварц стоит 16 МГц. Но на осцилографе упорно выходит синусоида 120 Гц :(
#include
#include
#include
#include
void hwInit(void);
unsigned char tmp = 0×00;
unsigned char sin_tab[] = {0,2,5,10,16,22,30,39,48,59,69,81,93,105,117,131,143,
155,165,179,190,201,210,220,228,235,241,247,251,253,254,
254,254,252,249,244,238,232,224,215,206,195,185,173,161,
149,137,124,111,99,87,75,64,53,44,34,26,19,13,7,3,1,0,0};
void main(void)
{
hwInit();
sei();
while (1);
}
void hwInit()
{
DDRB = (1<<DDB3);
// Fast PWM
TCCR1A = (0<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(1<<WGM10);
TCCR1B = (1<<WGM12)|(1<<CS10);
TIMSK1 = (1<<TOIE1)|(1<<OCIE1A);
// Timer 0 Overflow CTC
TCNT0 = 0;
TCCR0A = (1<<WGM01)|(1<<COM0A0);
TCCR0B = (1<<CS00);
TIMSK0 = 1<<TOIE0;
OCR0A = 0xFF;
}
ISR(TIMER1_COMPA_vect)
{
PORTB = (1<<PORTB3);
}
ISR(TIMER1_OVF_vect)
{
PORTB = (0<<PORTB3);
}
ISR(TIMER0_OVF_vect)
{
OCR1A = sin_tab[tmp++];
if(tmp == 64)
tmp = 0;
}
На выходе стоит ФНЧ.
Подскажите, как можно изменять её частоту в пределах от 120 Гц до 3 кГц. Спасибо!
а с какой частотой у тебя тикает таймер?
всем доброго дня! и всего лишь этого куска хватит для генерации шим на борту?
;FastPWM Init
SETB DDRD,4,R16 ; DDRD.4 = 1 Порты на выход
SETB DDRD,5,R16 ; DDRD.5 = 1
; Выставляем для обоих каналов ШИМ режим вывода ОС** сброс при совпадении.
; COM1A = 10 и COM1B = 10
; Также ставим режим FAST PWM 8bit (таймер 16ти разрядный и допускает
; большую разрядность ШИМ сигнала. Вплоть до 10 бит. WGM = 0101
; Осталось только запустить таймер на частоте МК CS = 001
OUTI TCCR1A,2<<COM1A0|2<<COM1B0|0<<WGM11|1<<WGM10
OUTI TCCR1B,0<<WGM13|1<<WGM12|1<<CS10
Да. Ведь шим у нас генерирует периферийный генератор на базе таймера. А значит нам надо запустить таймер нужным образом и все.
Ну а потом складывать данные в регистры сравнения OCR, получая нужную скважность.
ну и плюс описание макросов…
я скачал исходник ваш и не понял: так много нужно кода для генерации шим? в большую часть кода я не въехал. извините.
В исходнике, что в архиве для шима малая часть. Остальное это макросы, инициализация контроллера, организация главного цикла. Об этом в предыдущих частях курса по ассемблеру авр. Там последовательно это все накручивается.
Di, во-первых, громадное тебе спасибо за данный великолепный сайт! Кладезь инфы предельно доступным и живым языком ) он (точнее, ты )) явился моим проводником в мир микроконтроллеров. РЕСПЕКТИЩЕ!!!!
и маленький вопрос вдогонку ) есть такая вещь — ATtiny25. Там 4 канала АЦП и 4 выхода ШИМ. Но — очень мало ног на DIP. Вопрос — а их (все АЦП и ШИМ) как-нибудь можно заюзать одновременно? Заранее спасибо!
А они пересекаются? Если да, то нет. Т.к. ШИМ это выход, а АЦП это вход. И тебе придется выбрать что будет входом, а что выходом. В принципе, можно попробвать сделать схематический изврат. Поставить диоды снаружи и в некоторые моменты юзать как вход, а в некоторые как выход, а диод защитит датчик (или что там у тебя подает сигнал на вход ацп) от напряжение которое выйдет с шима. Но точность ацп от этого сильно пострадает да и вообще изврат еще тот. Тебе придется периодически выключать шим и мерить сигнал на ацп.
Пересекаются ) да еще как.. реальный иврат получится, ну его нафиг )
Доброго времени суток. Столкнулся со следующей проблемой: залил в контроллер (ATTiny2313 тактируется внешнем кварцем на 1МГц, согласовывающие конденсаторы на 18пФ) обычную программу-мигалку (частота 0.5Гц). Всё отлично работает, только иногда при включении частота увеличивается примерно в 3-4 раза, а потом через некоторое время (секунд 10) резко приходит в норму. Эффект такого увеличения частоты также наблюдался после долгой работы устройства (часов 8) и лечился только перезагрузкой. В момент аномалии на ноге XTAL2 контроллера вместо обычной синусоиды сложный нестабильный сигнал похожий на сумму синусоид с частотами 1МГц и 2МГц, в то время как на ноге XTAL1 – ровная синусоида 1МГц! Земля вроде разведена нормально, плата тщательно была промыта в УЗ-ванне и покрыта полиуретановым лаком. Вопрос в следующем: что может сбоить – китайский кварц, китайские конденсаторы или у Tiny бывают такие проблемы?
Возможно кварц некачественный и заводится не на основной гармонике или скачет туды сюды с гармоники на гармонику.
как можно синхронно запустить тикать таймер_0 (portB.3) и таймер_1 (portD.4 / portD.5) ?
[code]
LDI r16,(1<<PSR10)|(1<<PSR2)
OUT SFIOR,r16
[\code]
непомогает, первый стартует тот у кого раньше происходит запись в TCCR_ХХХ_
Есть в SFIOR бит TSM — остановка всех предделителей. Пишешь туда 1 — предделитель блокируется, таймеры встают. Инициализируешь их как надо, запускаешь. Записываешь в TSM 0 и все пошли синхронно.
да на gaw.ru в описании меги128 есть этот бит! а вот в мега16 что-то не могу его найти! и студия ругается…
SFIOR
Bit_7___6____5_____4_____3____2___1___0
– XMBK__XMM2__XMM1__XMM0__PUD – PSR10
SFIOR (мега8)
Bit_7___6____5_____4_____3____2___1___0
– XMBK__XMM2__XMM1__XMM0__PUD – PSR10
(mega16)
ADTS2 ADTS1 ADTS0 ADHSM ACME PUD PSR2 PSR10
Хм… слушай чето тоже найти не могу. Есть костыльное решение. Например записать в таймер значение со смещением в один-два такта, чтобы у того кто стартанет вторым была фора на его инициализацию.
по тексту: «Прескалер будет равен 64, таким образом, частота тиков таймера составит 125000 Гц.»
наверное опчатка «64″ -> «4″
так как 8 000 000 / 256 * 4 = 125000…
вопрос забыл задать :)
Как быть если мне нужно, что-бы частота ШИМа была например 20кГц или меньше? при тактовой МК = 8МГц?
Поставить нужный прескалер. Да хоть на 1024 и частота будет заметно меньше.
прескалер = 8 -> это значит за 8тактов процесора (8МГц), счетчик тикнет 1 раз?
(8000000/8) / 256 = 3906,25 Гц частота ШИМ (при минимальном делителе)
а нужно 20кГЦ… без делителя много с делителем маловато будет…
или я недогоняю как им пользавоться?
Нужно именно 20кгц? не больше не меньше? Тогда тут сложно. Придется подбирать частоты кварца и делителя.
по условию сказано ШИМ до 20кГц… можно меньше.
собственно говоря, дальше понятно… подбирать нужно частоту кристалла или реализовать программно с необходимыми задержками.
Откуда деление на 256? Речь то идет о частоте тиков таймера, а не о частоте их переполнения.
извеняюсь, но я тока учусь
по тексту:
«Частота получившегося ШИМ сигнала определяется просто: Частота процесора 8Мгц, таймер тикает до 256 с тактовой частотой. Значит один период ШИМ будет равен 8000 000/256 = 31250Гц. »
далее идет описание режима СТС… и там:
«Например, надо нам прерывание каждую миллисекунду…Пусть у нас частота 8Мгц.
Прескалер будет равен 64, таким образом, частота тиков таймера составит 125000 Гц. А нам надо прерывание с частотой 1000Гц. Поэтому настраиваем прерывание по совпадению с числом 125…»
Как тут получилось 125000?
ага все понял! пока писал…. 8000000/64 = 125000
«то получим самое обычное трехфазное напряжение, а значит привет бесколлекторные асинхронные и синхронные двигатели»
В процессе чтения возник вопрос – микроконтроллер способен давать микроскопические токи, соответственно ничего серьезнее детского моторчика он питать не сможет.
Как же тогда самолеты у авиамоделистов летают и промышленные приводы работают?
МК — даёт только управляющий сигнал на «драйвер» управления мотором…
а вот уже драйвер — тянет токи/напряжение необходимые двигателю для работы.
А что такое INCM TCNT ? написано, что счетчик циклов, но компилятор ругается, я по сайту просмотрел, таких макросов не нашел… что подключить чтбы студия схавала?
про биты COM1A1:COM1A0 и COM1B1:COM1B0 и
WGM11 и WGM10 вместе с битами WGM12 и WGM13 :
Жили-были три японца — Як, Як-Цедрак, Як-Цедрак-Цедрак-Цедрони.
Жили-были три японки — Цыпа, Цыпа-Дрипа, Цыпа-Дрипа- Дримпопони.
Все они переженились — Як на Цыпе, Як-Цедрак на Цыпе-Дрипе,
Як-Цедрак-Цедрак-Цедрони на Цыпе-Дрипе- Дримпопони.
И родились у них детки — У Яка с Цыпой — Шах, у Як-Цедрака с Цыпой-Дрипой — Шах-Шарах,
у Як-Цедрак-Цедрак-Цедрони с Цыпой-Дрипой- Дримпопони —
Шах-Шарах-Шарах-Шарони. :-))) хеппи хелоуин!
Это макросы относятся к организации программы вообще. Алгоритм шарманки, чтобы организовать временное разделение задач не используя никаких аппаратных ресурсов вообще. Показана для примера, т.к. в использовании не очень удобна и применяется редко. Но рулит если все таймеры надо выделить в дело (например, для генерации многих ШИМ Одновременно по всем таймерам). В конце статьи архив с исходниками примера и там все есть.
Спасибо. слона то я и не заметил(т.е. прикрепленный файл)
Просто хотел глянуть, как протеус будет реагировать на конфликт с запретом вложеного прерывания. реального осцила к сожалению нет.
Посмотрел, дребезг можно заметить, хоть и не так очевидно как на вашем настоящем, но хоть буду знать как выглядит.
З.Ы. В коде прикрепленного файла и других местах наверное ачипятка? :
OUTI TCCR1A,0<<COM1A0|0<<COM1B0|0<<WGM10|1<<WGM10 а надо
OUTI TCCR1A,0<<COM1A0|0<<COM1B0|0<<WGM11|1<<WGM10
думаю не критично -ведь бит WGM11 все равно равен 0.
Может биты ноликов вообще не обязательно выставлять ???
Начал изучать ASM по вашим урокам с месяц назад, очень доволен этим сайтом, огромное спасибо! С первой «получки» от контроллеров выставлюсь :-)
Да, разумеется 11.
Нолики можно и не выставлять. Просто удобно когда форма записи одна и та же и просто меняешь нолики на единицу, ничего не дописывая.
Здравстуйте! Не могли бы вы обьяснить чем отличаеться 8, 9 и 10 разрядный ШИМ?
Разрядностью :)
У 8ми разрядного 256 градаций скважности
у 9ти разрядного 512 у 10ти 1024.
Ну и, соответственно, скоростью (т.е. предельной частотой). 8ми разрядный шим прогоняет период за 256 тиков таймера, а 10и за 1024.
Спасибо))
цит: прямой ШИМ (сброс при совпадении и установка при обнулении счета)
простите,а установка чего? судя по графику какраз выход устанавливается в логическую 1 при совпадении со счетным регистром… или я не понимаю :(
ещё непонятный момент — мы устанавливаем !!!биты!!! СОМ1А1:СОМ1А0 =0b10 следующим образом: (2<<COM1A0)? т.е. 0 остается в COM1A0 а 1 переходит в СОМ1А1 чето запутано…
вопрос о Phase Correct PWM.
цит: Основное его предназначение, делать многофазные ШИМ сигналы, например, трехфазную синусоиду. Чтобы при изменении скважности не сбивался угол фазового сдвига между двумя ШИМ сигналами. Т.е. центры импульсов в разных каналах и на разной скважности будут совпадать.
А если центры импульсов не будут совпадать, разве это сильно повлияет на угол фазового сдвига? Сигнал то все-равно интегрируется…
не могли бы вы добавить пример с изменением частоты ШИМ или дать ссылку.
Заранее спасибо тем добрым людям кто захочет ответить :-Р
Устновка и сброс бита на выводе контроллера. А график сделан для какого то одного из режимов.
тут мы значение 10(2) сдвигаем на место с начлом в COM1A0. т.к. COM1A1:COM1A0 то получится, что COM1A1 =1, а COM1A0 = 0. Чем тормозить, лучше бы прогнал в эмуляторе и увидел сам что происходит. Изучать надо с компилятором под рукой, а не просто по тексту :)
Если у одного канала значение около 0, а у другого в районе 255 то фазы уплывут очень сильно. И толку что оно интегрируется? Возникнет куча паразитных вещей, искажение формы поля машины, лишние потери. Оно нам надо?
В конце статьи прикреплен исходник примера где два канала ШИМ меняются.
большое спасибо, постараюсь больше не тормозить)
Замечательная статья, уважаемый DI HALT, но в каком состоянии вы писали шестой ее абзац? :)
А что шестой абзац?
Уважаемый автор, спасибо огромное за создание и эксплуатацию этого сайта!
Если будет время то.. (Буду краток) -
Как проверить работоспособность МК(программатор Громова собрал, аттини2313v купил, аврСтудию поставил, в эмуляторе все работает-шим, в юнипроге все записывается — читается, в реале на ноге не появляется ни импульса ни лог1) — может я что-то пропустил?
Заранее спасибо)
!! УРА, Разобрался — в ресете проблема была.
Доброго времени суток, уважаемай комьюнити!
прошу посоветовать, как лучше реализовать амбилайт для ПК (была похожая статья на хабре, но там для 4 светодиодов, да и мерцания присутствуют).
Планирую использовать 6 RGB светодиодов (2 справа, 2 слева, 2 сверху), необходимо иметь возможность плавно менять яркость каждого из них (то есть 6х3= 18 ШИМ каналов). 18 аппаратных ШИМ каналов я не видел ни на одном МК АВР (допускаю что плохо искал), следовательно прийдется все каналы реализовывать програмно.
Будет ли работать следующая схема?
На выводы МК вешаю 3 сдвиговых 8битных регистра (3 вывода под data на каждый из регистров, и 1 вывод на тактовые входы сдвиговых регистров). Далее с выводов сдвиговых регистров через RC цепочку на светодиоды.
Данные цветности буду передавать в МК через usb.
Если схема работать будет, то:
- какой частоты должен быть ШИМ сигнал для светодиодов, чтобы глаз не замечал подвоха?
А может быть лучше использовать аппаратные драйверы светодиодов?
Посоветуйте, как лучше сделать?
Спасибо.
А сделать на двух МК релегия не позволяет? ;)
А разве есть МК с 9 аппаратными ШИМ кналами? Если нету — то все равно програмно реализовывать нужно, и какая уже разница на 1 или на 2 МК?
ARM Cortex M3 например. Но не суть. От частоты все зависит. Можно и программно, на конечном автомате сделать.
Если девайс штучный, то я бы не парился. Сварганил все на нескольких МК. Например Тини2313 может организовать 4 аппаратных ШИМ канала. Стоит недорого (около 50р). Пять тинек одна совмещенная с управлением всем этим борделем даст искомый результат. Тогда программная реализацию будет проще простого.
уточнение, мне нужно плавно регулировать яркость каждого из 3-х цветов светодиода, в итоге нужно 3 цвета х 6 светодиодов = 18 ШИМ каналов.
DM163 и ноги вам в руки, как раз для RGB светодиодов) Да еще можно их несколько последовательно цеплять..)
Прошу прощения, если уже обсуждалось. можно повысить частоту ШИМа, выбрав в битах WGM13:10 режим, когда топ не фиксированный 8, 9 или 10 бит, а задается регистром ICRx. К примеру, используя внутренние 8МГц и задав ТОП = 100 вместо 255 для 8-битного мы повысим максималльную частоту в 2.5 раза — до 80КГц
Проверил на практике — всё работает и даже вроде как надо, но осциллограф сказал бы точно :)
НУ да, только теряем в разрешении шима.
Хочу копировать значение регистра ADCH в регистр OCR2. Необходимо регулировать
скважность ШИМ входным аналогом. Пытаюсь через MOV. Студия показывает ошибку.
Подскажите пожалуста в чем дело и как можно по другому?
ПОтому что так нельзя. Сначало надо из ADCH через IN взять в R какой нибудь (в R16 например), а потом оттуда через OUT выгрузить в OCR2
Это тебе не х86 тут нельзя просто так гонять данные между памятью.
Кто ни будь может посоветовать статью без макросов? Они сложны для моего понимания…
Не, без макросов что без рук и ног. Что именно тебя смутило?
Видимо.. сами макросы :D
Я и сам до них не дошел.. другой синтаксис, неудобно, вот и пересел на Си.
SETB
При настройке портов на выход можно заменить на
SBI DDRB, 4
SBI DDRB, 5
А в следующем отрывке он уже используется для другого
SETB TIMSK,OCIE1A,R16 ; Включаем прерывание по сравнению А
SETB TIMSK,OCIE1B,R16 ; Включаем прерывание по сравнению Б
SETB TIMSK,TOIE1,R16 ; Включаем прерывание по переполнению Т1
Посмотрел исходник, там вообще шестнадцатеричным кодом всё написано)))
Эт хитрый макрос. Универсальный, сам определят тип адреса назначения и подставляет нужные комбинации
Нужно организовать на меге 8 воспроизведение заданой формы сигнала, например синусоиды, форма сигнала зашивается значениями амплитуды в массиве. Частота и амплитуда сигнала задается с клавы.
Идея такая: первый таймер делает быстрый шим, второй делает прерывания по сравнению через промежутки времени равные частоте, заданой в начале, деленной на количество точек в массиве, а в прерывании меняет регистр сравнения первого и заодно свой, чтобы прерваться в следующий раз через нужный промежуток времени.
Оцените идею =) Тут меня еще мучает вопрос будет ли прерываться работа шим первого таймера во время прерывания второго?
Нормально будет работать. ШИМ Же аппаратный. Идея тоже здравая. Я бы аналогично сделал.
Я прошу прощения за возможно не лепый вопрос
Подскажи пожалуйста, какой резистор и кондер ставить на RC фильтр и если можно дайте ссылки на их расчеты?
Да и еще, т.к. кондер от своего заряженного состояния может замыкать на землю ножку, не спалится так контролер? т.е. можно прям напрямую подключать кондер, ножка и земля?
Кондер электролит?
http://easyelectronics.ru/kondensator-i-rc-cepochka.html
Ногу контроллера нельзя напрямую к конденсатору подключать — может сгореть вывод контроллера. Только через резистор.
А если требуется управлять мощной нагрузкой с помощью шим, чем можно заменить RC цепочку?
Подцепить драйвер MOSFET и сам MOSFET
После RC цепи?
Вместо.
А на выходе будет постоянка?
На выходе с транзистора там будут мощные ШИМ импульсы.
А дальше от нагрузки зависит. Если нагрузка индуктивная, то их сгладит за счет индуктивности нагрузки. Если это нагреватель или осветитель, то там пофигу — сгладит тепловая инерция системы.
А как если нагрузка не индуктивная?
Если да кабы. Блок питания делается под нагрузку. От нее и надо плясать.
Вот тут, по-моему ошибка
[quote]
ШИМ на прерываниях.
Но вот засада — плата уже разведена, захотелось ШИМ, а выводы OCxx уже задействованы под другие цели.
…….
Пример:1
; ШИМ будет на выводах 3 и 6 порта D
SETB DDRD,3,R16 ; DDRD.3 = 1 Порты на выход
SETB DDRD,6,R16 ; DDRD.6 = 1
…………….
OUTI TCCR1A,0<<COM1A0|0<<COM1B0|[b]0<<WGM10[/b]|1<<WGM10
OUTI TCCR1B,0<<WGM13|1<<WGM12|1<<CS10
[/quote]
Два раза прописан WGM10.
Ой.. Поправил.
Спасибо большое за статью.
Получилось самому поиграть шимом и даже управлять драйвером для мощных светодиодов.
Вопрос вот у меня в чём. На днях увидел красивое видео
http://www.youtube.com/watch?v=V5hWZvli9as&feature=player_embedded
на атиньке можно, судя по всему 4 канала ШИМ использовать, а на этом видео, судя по всему 12 каналов работаю. Каким же образом?
Да запросто можно программно хоть 40 каналов сделать. Все зависит лишь от дискретности и обработки всего этого. Ну и загруженности процессора другими задачами.
вчера заметил ещё один глюк в Студии
в устройстве требовалось организовать простейший индиактор — чтобы светодиод периодически подмигивал — мол, живой я
без лишнего софта приспособил под это дело Timer1 в режиме Fast PWM просто загрузкой OCR1A и ICR1A
Студия категорически отказалась показывать реальную картину, хотя в железе — «картина маслом»
так что прежде чем биться лбом об стену — проверяйте в железе
Автору огромное спасибо, очень подробно и доходчиво всё разжевано:)
я только недавно начал изучать AVR,
есть одно замечание- косяк скорее мой в том что не заметил сразу «Исходник к статье», а в нем описаны макросы, которые применялись, в статье толком об этом не говорится, скачал, увидел как всё это работает, теперь доволен как таракан :-D
Эти макросы вводятся по ходу курса и в момент ввода подрбоно описываются.
Подскажите:
на вход компаратора подаю синус 50Гц и пилу 20кГц. Как влияет разница амплитуд синуса и пилы на входе компаратора на характер сигнала на выходе компаратора?
Доброго времени суток! Стоит задача задавать управляющее напряжение для ГУН’а посредством ШИМ и интегрирующей RC-цепочки. В железе все давно собрано, сейчас дошел до программной реализации ШИМ и столкнулся с проблемой. Чтобы после RC-цепочки (10КОм, 10мкФ) не было пульсаций требуется частота выше 100КГц (если верить Proteus то идеално под 200КГц), а это у меня не получается. Аппаратно можно сделать только ~37КГц. Пробывал реализовать программно с большей частотой, но не получилось.
Может кто знает как можно решить эту проблему?
Заранее благодарен.
Вариантов тут немного. Можно понизить разрядность ШИМ’а и тогда он будет щелкать быстрей. Скажем сделать его 5ти разрядным ,ограничив TOP в режиме FastPWM
Можно взять другой МК. Например Tiny45 имеет встроенный PLL позволяющий разгонять тактование таймеров до 40 чтоль МГЦ. Соответственно получить тут 200кГц не должно стать проблемой.
Странно что-то у меня с ATTiny25.
Режимы — COM1B
0 0 — отключен от пина
0 1 — при совпадении с OC1B — пин меняет состояние на противоположное (т.е. H/L 50/50)
1 0
1 1 — шима вообще нет (один раз пин переключается в 1 или 0 и все)
Изучил даташит — в непонятках. Начал научным тыком — нашел. Надо ставить в единицу бит PWM1B в GTCCR. Очень логично, конечно, если бы не описание
«Bit 6 – PWM1B: Pulse Width Modulator B Enable
When set (one) this bit enables PWM mode based on comparator OCR1B in Timer/Counter1
and the counter value is reset to $00 in the CPU clock cycle after a compare match with OCR1C
register value.» Т.е. при чем тут OCR1C — не понятно. И почему когда этот бит выставил, и выставил COM в 0 1 — заработал нормальный ШИМ (до OCR еденица, после — ноль)
Ну так все верно.
Ты включаешь битом PWM1B модулятор. А ШИМ формируется путем сравнения значения в TCNT с значением в OCRxx меняя значение в OCR1B мы задаем скважность.
А OCR1C задает максимальное значение счета. Выше было сказано:
» OCR1C holds the Timer/Counter maximum value, i.e. the clear on compare match value. In the normal mode an overflow interrupt (TOV1) is generated when Timer/Counter1 counts from $FF to $00, while in the PWM mode the overflow interrupt is generated when Timer/Counter1 counts either from $FF to $00 or from OCR1C to $00. The inverted PWM outputs OC1A and OC1B are not connected in normal mode.»
«When set (one) this bit enables PWM mode based on comparator OCR1B in Timer/Counter1 and…» дальше нужно было не читать. Сбило с толку)
Спасибо за пояснение. Каждый раз удивляюсь, как много внимания Вы уделяете порталу. Еще раз спасибо!
А где бы по подробнее узнать о трехфазной синусоиде?
А то в сети находил только однофазные примеры с использованием специальных таблиц.
Так если у тебя есть таблица одной синусоиды, то вторая и третья берется из нее же, только берешь из ячейки со сдвигом в 120 градусов и все.
Мне хотелось бы регулировать частоту но с математикой у авр (я так понял) пробелмы.Я вот думаю как будет эфектинее,зделать еще одну таблицу со сдвигами или расчитывать значение перед запуском шима ?
Частота задается всего лишь скоростью выборки из таблицы. Для более менее ровного синуса тебе за глаза хватит 30-40 точек в таблице.
Тоесть чем меньше частота тем реже пихаем значение в регистр?
Ага. Т.е. надо тебе 1гц — пробегаешь по таблице за 1секунду. Надо тебе 100гц — 100 раз в секунду. И так пока не упрешься либо в быстродействие МК (на выборку уйдет не меньше трех пяти тактов). Либо в частоту ШИМа которая не будет успевать перестроиться.
Спасибо теперь попробую написать код.
Здравствуйте! Хочу сказать Вам огромное спасибо за огромное количество (и качество!!) информации на Вашем сайте.
А еще возник такой вопрос — мне нужно, чтобы значение в OCR менялось в зависимости от значения , принимаемого АЦП. Ну т.е есть переменный резистор, мы его покрутили, АЦП обработал, и в зависимости от этого значения поменялся порог сравнения (ширина импульсов). Что во что запихивать в таком случае? Буду оооочень признательна за совет!!
В прерывании по окончанию замера ацп сделать внесение нужного значения в OCR вот и все. Если надо напрямую, то OCR = ADC. Ну или зависимость какую прописать
спасибо за оперативный ответ, мне почему-то казалось , что нельзя прям из АЦП кидать в ОСR , но научного обоснования этому нет. буду пытаться написать код!
и еще вопрос — я возможно пропустила какие-то начальные уроки введения в курс, где можно прочитать пояснение такого типа записи :
OUTI TCCR1A,0<<COM1A0|0<<COM1B0|0<<WGM11|1<<WGM10
OUTI TCCR1B,0<<WGM13|1<<WGM12|1<<CS10
Ну напрямую нельзя. Т.е.
сначала IN Rxx , ADCH
потом OUT OCR, Rxx
Т.е. через регистр. Также учитыввай тот факт что OCR может быть как 16ти так и 8ми разрядным, в зависимости от разрядности таймера, а результат АЦП может быть как 8ми (выравнивание влево, младшие биты не читаем, берем из ADCH) так и 10 разрядным из двух байт ADCH и ADCL.
Это просто макрос. OUTI
раскрывается в
LDI R16,0<<COM1A0|0<<COM1B0|0<<WGM11|1<<WGM10
OUT TCCR1A,R16
Сам макрос у меня описан где то в исходниках в файле macro.inc или что то подобное.
Уже не первый раз сталкиваюсь с такой вещью: при работе счётчиков в режиме FastPWM, выход подключен «Clear OC2 on Compare Match, set OC2 at BOTTOM,(non-inverting mode)», при OCRxx=0×00 на выходе мк нет нулевого уровня, а присутствуют пики длительностью в такт таймера (смотрел осциллографом), что фактически равносильно OCRxx=0×01. При этом, естественно, чуть светится светодиод (а мощный — достаточно ярко) подключенный к этому выходу. Даташит это явление подтверждает (стр.104 для atmega16): «The extreme values for the OCR1x Register represents special cases when generating a PWM waveform output in the fast PWM mode. If the OCR1x is set equal to BOTTOM (0×0000) the output will be a narrow spike for each TOP+1 timer clock cycle. Setting the OCR1x equal to TOP will result in a constant high or low output (depending on the polarity of the output set by the COM1x1:0 bits.)». В результате приходилось использовать Phase Correct PWM. Вот мне и интересно, почему у Вас он регулируется от нуля?
У меня тоже иголки там есть. В один такт.
Я так понял, если подключить стрелочный вольтметр к выходу МК, то никаких дополнительных примочек не надо.
Вопрос в том, какой максимальный ток может отдать микруха, и можно ли присоединять напрямую к ногам, или нужно ставить буффер\транзистор\?
Разобрался! Нашел в даташите Absolute Maximum Ratings — DC Current per I/O Pin.
«Вывод OCxx при первом совпадении сбрасывается, при втором устанавливается»
Сдесь не наоборот должно быть?
Или это настраивается как в fast pwm ?
Поведение OC выводов настраивается
Доброе время суток!
Написала программу (делаю ШИМ регулируемый резистором), компилирую, АВР-студия ругается на » .ORG $01C rjmp ADC ; ADC Conversion Complete Handler» , хотя как и другие вектора прерываний эта строчка скопирована из даташита! Но именно на ADC ругается. Как так?
Еще такой нюанс — прерывание АЦПшника занимает больше места,чем другие? если два байта отведено, то он пишет про конфликт адресов : » C:\avr\pwm1.asm(38): error: Overlap in .cseg: addr=0x1e conflicts with 0x1c:0x1f »
а если пишу вот так, то уже не ругается на адреса:
.ORG $01C rjmp ADC ; ADC Conversion Complete Handler
reti
.ORG $020 rjmp EE_RDY ; EEPROM Ready Handler
reti
И еще выдает такую ошибку «C:\avr\pwm1.asm(93): error: Operand(s) out of range in ‘ldi r16,0x45f’ «, скажите, пожалуйста, что с этим делать!
жду вашей помощи! )
Ох, прошу прощения за дурацкий вопрос!! уже разобралась, там же перед rjmp надо было закомментить.. больше ничего вышеописанного Студия не выдает!!
я просто читала где-то другой способ описания таблицы векторов, без .ORG, но почему-то он не работает) теперь почти все в порядке))
И все же никак не могу устранить причину ошибки
C:\avr\pwm1.asm(73): error: Operand(s) out of range in ‘ldi r16,0x45f’
В чем может быть дело??
з.ы. — а тут нельзя удалять свои комменты, если уже нашел ответ на вопрос? конечно, 7 раз подумай, 1 раз спроси, но так получилось..
Пытаешься впихуть невпихуемое. Регистр может вместить значение не больше чем 255. А 0x45F нааамного больше. Такое число может влезть только в два байта (регистра) и обрабатываться побайтно. Как старший и младший байты.
LDI R16,LOW(0x45F)
LDI R17,HIGH(0x45F)
Ошибка , похоже, была связана с корявой инициализацией стека, старший байт сначала не указала.
Теперь все компилируется, шагает, но почему-то не выполняется простая команда :
ldi R16, 0b11111111 ; В OCR 0*FF , на выходе будет сигнал выс.уровня
(пока не придет значение с АЦП и не закинется в OCR)
out OCR2, R16
и с прерыванием по переполнению никак не подружусь, не шагает он на него, даже когда происходит само переполнение и флажок выставляется..
а на то,что описано в обработчике прерываний, никак стрелка не встает.
в табл.векторов написано:
.ORG $000 rjmp RESET ; Reset Handler
.ORG $002 ;rjmp EXT_INT0 ; IRQ0 Handler
reti
.ORG $004 ;rjmp EXT_INT1 ; IRQ1 Handler
reti
.ORG $006 ; rjmp TIM2_COMP ; Timer2 Compare Handler
reti
.ORG $008 rjmp TIM2_OVF ; Timer2 Overflow Handler
.ORG $00A ; rjmp TIM1_CAPT ; Timer1 Capture Handler
reti
(и далее)
А в обработчике прер-я:
TIM2_OVF: in R17, ADCH ;
out OCR2, R17
reti ;выход из обработчика прер-я АЦП
перед обработчиком — бесконечный цикл для ожидания прерывания..
Чето у тебя какая то странная таблица векторов.
Не поленись возьми и по даташиту выстави все вектора какие есть. На те которые надо поставьи RJMP, а ненужные затерминаль на reti.
А прерывания разрешены локально и глобально? Без этого флажок может и встанет, но реакции не будет.
Также можешь поглядеть куда уходит программа если включишь режим дизассемблера и потрассируешь там. Там будут видны все адреса, а не только те что в программе расписаны.
Ну и в обработчике прерывания у тебя косяк. Ты меняешь регистр R17, а в стеке его не сохраняешь. Если он у тебя используется где то в программе может возникнуть трудно уловимый плавающий глюк.
Таблицу векторов я просто тут не стала всю размещать,вместо остальных векторов из даташита написано «(и далее)». Смотрела выше в описаниях ваших, вроде бы сделала все по аналогии. Т.е мне нужны только reset и по переполнению TIM2_OVF:
.ORG $000
rjmp RESET ; Reset Handler
.ORG $002 ;rjmp EXT_INT0 ; IRQ0 Handler
reti
.ORG $004 ;rjmp EXT_INT1 ; IRQ1 Handler
reti
.ORG $006 ; rjmp TIM2_COMP ; Timer2 Compare Handler
reti
.ORG $008
rjmp TIM2_OVF ; Timer2 Overflow Handler
.ORG $00A ; rjmp TIM1_CAPT ; Timer1 Capture Handler
reti
.ORG $00C ;rjmp TIM1_COMPA ; Timer1 CompareA Handler
reti
.ORG $00E ;rjmp TIM1_COMPB ; Timer1 CompareB Handler
reti
.ORG $010 ;rjmp TIM1_OVF ; Timer1 Overflow Handler
reti
.ORG $012 ;rjmp TIM0_OVF ; Timer0 Overflow Handler
reti
.ORG $014 ;rjmp SPI_STC ; SPI Transfer Complete Handler
reti
.ORG $016 ;rjmp USART_RXC ; USART RX Complete Handler
reti
.ORG $018 ;rjmp USART_UDRE ; UDR Empty Handler
reti
.ORG $01A ;rjmp USART_TXC ; USART TX Complete Handler
reti
.ORG $01C ;rjmp ADC ; ADC Conversion Complete Handler
reti
.ORG $020 ;rjmp EE_RDY ; EEPROM Ready Handler
reti
.ORG $022 ;rjmp ANA_COMP ; Analog Comparator Handler
reti
.ORG $024 ;rjmp TWSI ; Two-wire Serial Interface Handler
reti
.ORG $026 ;rjmp SPM_RDY ; Store Program Memory Ready Handler
reti
А прерывания разрешены в TIMSK (это и называется локально?) и глобально — sei.
Reset: ldi R16, (1<<DDB3) ; вывод ОС2 ( порт В, 3 бит) на выход
out PORTB, R16
ldi Temp, 0b01101100 ; настройка режима работы Т/С2, в т.ч. CLK/64, быстрый ШИМ и При совпадении ноль
out TCCR2, Temp
ldi Temp, 0b01000000 ; Bit 6 – TOIE2 установлен, разрешает прерывание по переполнению
out TIMSK, Temp
; Инициализация стека (как в вашем примере)
;настройка АЦП
ldi R16, (1<<ADLAR) ; выравнивание слева (результат в старших разрядах)
out ADMUX, R16
sei ;разрешить прерывания
;****************************************************
; ОСНОВНОЙ ЦИКЛ
;**************************************************
begin:
ldi R16, 0b11100000
out ADCSRA, R16
ldi R16, 0b11111111 ; ПОЛОЖИТЬ В OCR 0*FF ;
out OCR2, R16 ; А НИЧЕГО НЕ ПРОИСХОДИТ …
Inf: rjmp Inf ;бесконечный цикл — ждем прерывания
TIM2_OVF: in R17, ADCH ; СЮДА ОН НИКОГДА НЕ ПОПАДАЕТ
out OCR2, R17
reti ;выход из обработчика прер-я АЦП
Больше R17 нигде не используется, все равно сохранять в стек?
УЖЕ СНОВА НАШЛА ОШИБКУ и заданные выше вопросы кажутся глупыми! =)
Проблема с прерыванием заключалась в том,что в таблице векторов у меня неправильно прописаны адреса, 000 -> 002 -> 004, я читала Ваш пример ШИМа и на автомате написала адреса как в примере, а не как в даташите на мою 8 атмегу :)
.ORG $000
rjmp RESET ; Reset Handler
.ORG $001 ;rjmp EXT_INT0 ; IRQ0 Handler
reti
.ORG $002 ;rjmp EXT_INT1 ; IRQ1 Handler
reti
.ORG $003 ;rjmp TIM2_COMP ; Timer2 Compare Handler
reti
.ORG $004
rjmp TIM2_OVF ; Timer2 Overflow Handler
(и прочие вектора)
Теперь обработчик прерывания работает, на него стрелка прыгает, действие выполняется.
А вот по команде (напишу ее пока так,как писала я) ничего не происходит:
ldi R16, 0b11111111 ; ПОЛОЖИТЬ В OCR 0*FF ; на выходе будет лог. 1
out OCR2, R16 ;
Но в общем-то программа может работать и без этого) Возможно, OCR нельзя обновить в то время, когда считает таймер-счетчик, и можно обновить только в момент переполнения , к началу нового периода.. ?
Теперь остался какой-то странный глюк, что значение в ОСR из АЦП кладется с отставанием .
Т.е кладу в АЦП 0200 (нужен старший байт,т.е в ОСR будет 02) . таймер переполнился, в обработчике прерывания кладем значение АЦП в OCR, но ничего не происходит, там ноль как и был.
Меняю значение в АЦП (пусть 03) в обработчике прерывания по переполнению таймера в OCR кладется… прежнее значение — 02.
По следующему переполнению в OCR положится 03 и т.д., т.е кладется не текущее значение, а предыдущее!
Буду искать причины) Спасибо за советы!
OCR можно обновлять в любое время. Шим правда немножко сбиваться будет, но не во всех режимах. В некоторых у него аппаратно выровняется на следующем проходе. В общем надо ДШ смотреть конкретней. Единственно, OCR 8ми разрядный или 16ти? Если 16ти, то там хитрый порядок доступа к его байтам. Сначала вроде бы младший, потом старший. Иначе его переклинивает. В даташите это отдельным пунктом оговорено в разделе про таймер (что то вроде подраздела «Доступ к 16ти разрядным регистрам). Почитай там.
А отставание насколько? Если на один период ШИМ, то вроде как так и должно (то самое выравнивание)
Да, локально это бит разрешения конкретного прерывания. Ну а глобально флаг I в регистре sreg.
Если R17 нигде не используется и не будет использоваться, то можно не сохранять в стек. Главное про это ПОМНИТЬ! А то решишь потом заюзать и получишь вилы в бок.
Без ORG тоже можно. Такое работает если длина вектора прерывания 2 байта, а мы туда ставим одну команду. В итоге, просто нужное количество RETI или RJMP. Но если взять контроллер у которого много памяти, то вектор там уже четырехбайтный, чтобы вместить большую команду JMP
Ну либо делать этажерку RETI NOP, но это коряво.
привет всем!!подскажите пожалуйста, нужно реализовать ШИМ но чтобы выходное значение быстро реагировало на опорное напряжение, т.е. задумка такая есть через ацп измерять, что то делать а потом кидать в регистр OCR…но загвоздка тут в том, что нужно оч оч часто обновлять значения регистра OCR а по программе этого не получается…есть два варианта использовать другой МК, в котором будет чисто измерение опорного напряжения и выдача ШИМ, либо второй — как то по мудрить с программой…может кто то сталкивался с проблемой, подскажите плиз.
ШИМ у тебя один фиг должен перезарядить конденсатор, чтобы застабилизировать напряжение. Т.е. это два, а лучше три периода ШИМ импульса. Т.е. если ты хочешь реально быстро это сделать, то юзай внешний ЦАП. Например на R2R резистивной цепи (если не нужна большая разрядность) или спец микруху применить. На крайняк можно заюзать STM32 где ЦАП во многих чипах идет по дефолту.
по про бывал сделать шим из таймера T1, сигналы вроде получил, но как то коряво получилось..проблема в том, что кидаю значения в регистры OCR1AH и OCR1AL…когда кидаю в младший регистр число(старший нули) на выходе не оч хорошая картина получается. если же на оборот в старший число(младший нули) на выходе прямоугольники на RC цепочке пила, но она не очень острая, заряжается не по прямой а по экспоненте…как сделать чтобы была прямая линия зарядки?? номинал изменить и еще объясните с регистрами, запутался.
DI HALT, подскажите, как можно вывести ШИМ на весь порт для запуска электродвигателя, на ATmega8535
Что значит на весь порт? Ты хочешь от порта запитать двигатель? Плохая идея.
а как лучше сделать, управляя 6 транзисторами, на выходе получить трехфазный синусоидальный ток
Самый лучший способ — применить AVR серии pwm или как то так. Там как раз будет 6 каналов ШИМ с dead time и прочими прелестями. Ну либо обычная мега с тремя каналами шим, на полумостовые драйверы.
А как сделать программно из 3 каналов ШИМ (у ATmega8535 4 канала ШИМ)6 каналов и управлять ими, попарно включая/выключая?
Красиво не получится. Единственный вариант — сделать тут по прерываниям сравнения и переполнения и включать-выключать выводы вручную. Но это будет во первых медленно, во вторых будет джиттер изза того, что прерывание может быть заблокировано другим прерыванием.
то есть для лучшего управления, лучше использовать AVR серии PWM? Там выводы переключаются проще?
Там не проще, а специально для этого все сделано. Аппаратно. Т.е. у каждого шим канала два выхода, прямой и инверсный. Причем они не тупо переключаются один в 1 другой в 0 и наоборот, а с задержкой, чтобы ключи успели закрыться.
спасибо, как разберусь с этим я напишу, мой почтовый ящик okaun@mail.ru, пришлите мне свой адрес и я буду задавать вам вопросы по почте
Размечтался :)
У меня возник вопрос. Будет ли меняться уровень постоянной составляющей, при неизменной скважности, но разной частоте?
Т.е. отношение сигнал/нет сигнала на выходе одно, а частота меняется, то подключенный, скажем, диод будет светить одинаково или нет?
Я замудрил просто программный шим, но он будет прерываться, т.к. нужна многозадачность. И получается так, что от величины паузы в подпрограмме программного шим, которая равна величине обработки какой нить другой подпрограммы, зависит частота этого самого шим, но скважность там меняться не будет, я предполагаю, что светодиод будет гореть так же с одинаковой яркостью, или не так?
а, да, шим будет прерываться в каждом цикле
а, нет не в цикле, а в каждом такте
Да зависит. С программным шимом всегда так. Более менее стабильную частоту и скважность можно получить только на гибридном ШИМ, т.е. где смена уровней идет по прерыванию таймера в конечном автомате. И сделать так, чтобы это прерывание никто не мог перебить на ощутимое время.
От фильтра зависит. По идее не должен. Но по факту того же диода может меняться яркость, т.к. глаз штука накопительная и если световой заряд в сетчатке глаза рассасывается быстрей чем набивается новый, то общая яркость будет падать.
ок спс за ответ, там думаю частота будет на десятки килогерц (а мож и сотни хз пока) так что вроде глазу должно быть пофиг, волнует сам светодиод — на них не найдешь даташит, хотя вроде там должен быть параметр за какое время он доходит до определенной яркости — от этого наверное и будет зависеть все. Короче пока мк не прошью не узнаю (( в протеусе хрен проверишь такое )
===
Как мы и запланировали. С первого канала длительность импульса в 1/3 периода, а со второго в 1/2
===
тут не наоборот должно быть?
вроде на рис. на первом канале 1/2
спасибо
Здравствуйте
А можно на аппаратном 8bit ШИМе ATmega16 (Timer0 или Timer2) обеспечить частоту 50Гц для управления серво?
Хочу тремя сервами одновременно поуправлять, да так, чтоб с наименьшей нагрузкой на процессорное время.
Даташит курил, после расчетов по формуле f_oc=f_clk/N*510 в Phase Correct PWM Mode пришел к выводу, что это надо подбирать кварц по-точнее и то, из доступных в продаже наименьшая погрешность оказалась 6% при частоте кварца 6,144000 МГц и делителе 256. А мне потом еще и по UART рулить этим контроллером предстоит, боюсь, что такой кварц с уартом уже совсем большую погрешность даст.
неужели только программная реализация ШИМ для трех серво одновременно возможна (для ATmega16)?
Можно. А зачем? Нагрузка от конечного автомата обработки сервы мизерная, а таймер ценный ресурс который просерать на сервы ломы. Попробуй так:
http://easyelectronics.ru/upravlenie-mnozhestvom-servomashinok.html
Спасибо, большое! ))
А как быть если OC3C на Atmega128 не работает и в протеусе и в железе?. точнее работает но до записи в OCR3C. стоит записать в регистр сравнение хоть что нибудь перестает работать.. в любом режиме шима.
AvrStudio4, C++.
и вообще возможно ли всеми 6 ШИМами пользоваться независимо друг от друга? то есть во все регистры сравнения забить разные значения чтоб все 6 каналов давали разные частоты? когда в регистрах одинаковые данные (OCR1A,OCR1B,OCR1C) всё работает а когда настроены по разному работает только OCR1A
Есть вопрос.
Речь о программном ШИМе.Автор пишет «Таким образом, на один таймер можно повесить дофига ШИМ каналов….».
А можно ли сделать для каждого канала свою скважность тем способом которые указан в статье (на двух обработчиках прерываний)?если можно, то как?
Можно, если частота небольшая. Можно сделать хоть десять каналов. На конечном автомате и одном таймере. Почитай статью «Управление множеством сервомашинок» там есть такое.
спасибо за наводку.буду разбираться)
Подскажите, почему нельзя в ходе цикла изменить OCR1AL???
Как только пишу INC цикле, компилятор не ругается а Протеус мгновенно выстреливает с ошибкой.
Вот пример кода:
http://easyelectronics.ru/repository.php?act=view&id=89
Предпологаю что надо обнулить TCNT …
Но почему нельзя прямо???
ААа — запарил с подпрограммой )
Можно. Протеус не аргумент, в нем глюков и кривостей эмуляции дохрена.